<!DOCTYPE html>
<html lang=zh>
<head>
    <meta charset="utf-8">
    
    <title>为什么分布式一定要有Redis？ | YLFJM的博客</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
    <meta name="description" content="考虑到绝大部分写业务的程序员，在实际开发中使用 Redis 的时候，只会 Set Value 和 Get Value 两个操作，对 Redis 整体缺乏一个认知。 所以我斗胆以 Redis 为题材，对 Redis 常见问题做一个总结，希望能够弥补大家的知识盲点。">
<meta name="keywords" content="转载,Redis">
<meta property="og:type" content="article">
<meta property="og:title" content="为什么分布式一定要有Redis？">
<meta property="og:url" content="https://ylfjmy.gitee.io/2018/12/10/为什么分布式一定要有Redis？/index.html">
<meta property="og:site_name" content="YLFJM的博客">
<meta property="og:description" content="考虑到绝大部分写业务的程序员，在实际开发中使用 Redis 的时候，只会 Set Value 和 Get Value 两个操作，对 Redis 整体缺乏一个认知。 所以我斗胆以 Redis 为题材，对 Redis 常见问题做一个总结，希望能够弥补大家的知识盲点。">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="https://ylfjmy.gitee.io/2018/12/10/为什么分布式一定要有Redis？/1.webp">
<meta property="og:image" content="https://ylfjmy.gitee.io/2018/12/10/为什么分布式一定要有Redis？/2.webp">
<meta property="og:image" content="https://ylfjmy.gitee.io/2018/12/10/为什么分布式一定要有Redis？/3.webp">
<meta property="og:updated_time" content="2018-12-10T03:37:34.734Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="为什么分布式一定要有Redis？">
<meta name="twitter:description" content="考虑到绝大部分写业务的程序员，在实际开发中使用 Redis 的时候，只会 Set Value 和 Get Value 两个操作，对 Redis 整体缺乏一个认知。 所以我斗胆以 Redis 为题材，对 Redis 常见问题做一个总结，希望能够弥补大家的知识盲点。">
<meta name="twitter:image" content="https://ylfjmy.gitee.io/2018/12/10/为什么分布式一定要有Redis？/1.webp">
    

    

    
        <link rel="icon" href="/favicon.ico" />
    

    <link rel="stylesheet" href="/vendor/font-awesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="/vendor/open-sans/styles.css">
    <link rel="stylesheet" href="/vendor/source-code-pro/styles.css">

    <link rel="stylesheet" href="/css/style.css">

    <script src="/vendor/jquery/2.1.3/jquery.min.js"></script>
    
    
        <link rel="stylesheet" href="/vendor/lightgallery/css/lightgallery.min.css">
    
    
    
    
    



</head>

<body>
    <div id="container">
        <header id="header">
    <div id="header-main" class="header-inner">
        <div class="outer">
            <a href="/" id="logo">
                <i class="logo"></i>
                <span class="site-title">YLFJM的博客</span>
            </a>
            <nav id="main-nav">
                
                    <a class="main-nav-link" href="/.">YLFJM</a>
                
                    <a class="main-nav-link" href="/archives">归档</a>
                
                    <a class="main-nav-link" href="/categories">分类</a>
                
                    <a class="main-nav-link" href="/about">关于我</a>
                
            </nav>
            
                
                <nav id="sub-nav">
                    <div class="profile" id="profile-nav">
                        <a id="profile-anchor" href="javascript:;">
                            <img class="avatar" src="/css/images/logo.jpg" />
                            <i class="fa fa-caret-down"></i>
                        </a>
                    </div>
                </nav>
            
            <!--
<div id="search-form-wrap">

    <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="搜索"><button type="submit" class="search-form-submit"> </button><input type="hidden" name="sitesearch" value="https://ylfjmy.gitee.io"></form>

</div>
-->
        </div>
    </div>
    <div id="main-nav-mobile" class="header-sub header-inner">
        <table class="menu outer">
            <tr>
                
                    <td><a class="main-nav-link" href="/.">YLFJM</a></td>
                
                    <td><a class="main-nav-link" href="/archives">归档</a></td>
                
                    <td><a class="main-nav-link" href="/categories">分类</a></td>
                
                    <td><a class="main-nav-link" href="/about">关于我</a></td>
                
                <td>
                    
    <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="搜索"><input type="hidden" name="sitesearch" value="https://ylfjmy.gitee.io"></form>

                </td>
            </tr>
        </table>
    </div>
</header>

        <div class="outer">
            
                

<aside id="profile">
    <div class="inner profile-inner">
        <div class="base-info profile-block">
            <img id="avatar" src="/css/images/logo.jpg" />
            <h2 id="name">YLFJM</h2>
            <h3 id="title">Java程序猿</h3>
            <span id="location"><i class="fa fa-map-marker"></i>Shanghai, China</span>
            <!--<a id="follow" target="_blank" href="">关注我</a>-->
        </div>
        <div class="article-info profile-block">
            <div class="article-info-block">
                10
                <span>文章</span>
            </div>
            <div class="article-info-block">
                9
                <span>标签</span>
            </div>
        </div>
        
        <div class="profile-block social-links">
            <table>
                <tr>
                    
                    
                    <td>
                        <a href="http://github.com/ylfjm/" target="_blank" title="GITHUB" class=tooltip>
                            <i class="fa fa-github"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="https://gitee.com/ylfjmy/" target="_blank" title="码云" class=tooltip>
                            <i class="fa fa-gg"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="mailto:bozwork@163.com" target="_blank" title="邮件" class=tooltip>
                            <i class="fa fa-envelope"></i>
                        </a>
                    </td>
                    
                </tr>
            </table>
        </div>
        
    </div>
</aside>

            
            <section id="main"><article id="post-为什么分布式一定要有Redis？" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 class="article-title" itemprop="name">
            为什么分布式一定要有Redis？
        </h1>
    

                
                    <div class="article-meta">
                        
    
        
        <span class="label label-warning"
              style="float: left;padding: 3px 5px 3px 5px;margin-right: 15px;
                      margin-top: 3px; font-size: 0.9em;">转载</span>
        
    
        
    

                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/12/10/为什么分布式一定要有Redis？/">
            <time datetime="2018-12-10T03:21:16.000Z" itemprop="datePublished">2018-12-10</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/Redis/">Redis</a>
    </div>

                        <!-- 
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/Redis/">Redis</a>, <a class="tag-link" href="/tags/转载/">转载</a>
    </div>
 -->
                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>考虑到绝大部分写业务的程序员，在实际开发中使用 Redis 的时候，只会 Set Value 和 Get Value 两个操作，对 Redis 整体缺乏一个认知。</p>
<p>所以我斗胆以 Redis 为题材，对 Redis 常见问题做一个总结，希望能够弥补大家的知识盲点。</p>
<a id="more"></a>
<p>本文围绕以下几点进行阐述：</p>
<ul>
<li><strong>为什么使用 Redis</strong></li>
<li><strong>使用 Redis 有什么缺点</strong></li>
<li><strong>单线程的 Redis 为什么这么快</strong></li>
<li><strong>Redis 的数据类型，以及每种数据类型的使用场景</strong></li>
<li><strong>Redis 的过期策略以及内存淘汰机制</strong></li>
<li><strong>Redis 和数据库双写一致性问题</strong></li>
<li><strong>如何应对缓存穿透和缓存雪崩问题</strong></li>
<li><strong>如何解决 Redis 的并发竞争 Key 问题</strong></li>
</ul>
<h2 id="为什么使用-Redis"><a href="#为什么使用-Redis" class="headerlink" title="为什么使用 Redis"></a>为什么使用 Redis</h2><p>我觉得在项目中使用 Redis，主要是从两个角度去考虑：性能和并发。</p>
<p>当然，Redis 还具备可以做分布式锁等其他功能，但是如果只是为了分布式锁这些其他功能，完全还有其他中间件，如 ZooKpeer 等代替，并不是非要使用 Redis。因此，这个问题主要从性能和并发两个角度去答。</p>
<h4 id="性能"><a href="#性能" class="headerlink" title="性能"></a>性能</h4><p>如下图所示，我们在碰到需要执行耗时特别久，且结果不频繁变动的 SQL，就特别适合将运行结果放入缓存。这样，后面的请求就去缓存中读取，使得请求能够迅速响应。</p>
<p><img src="/2018/12/10/为什么分布式一定要有Redis？/1.webp" alt="img"></p>
<p><strong>题外话：</strong>忽然想聊一下这个迅速响应的标准。根据交互效果的不同，这个响应时间没有固定标准。</p>
<p><strong>不过曾经有人这么告诉我：</strong>“在理想状态下，我们的页面跳转需要在瞬间解决，对于页内操作则需要在刹那间解决。</p>
<p>另外，超过一弹指的耗时操作要有进度提示，并且可以随时中止或取消，这样才能给用户最好的体验。”</p>
<font color="rubine">那么瞬间、刹那、一弹指具体是多少时间呢？</font>

<p><em>根据《摩诃僧祗律》记载：</em></p>
<p><em>一刹那者为一念，二十念为一瞬，二十瞬为一弹指，二十弹指为一罗预，二十罗预为一须臾，一日一夜有三十须臾。</em></p>
<p>那么，经过周密的计算，一瞬间为 0.36 秒、一刹那有 0.018 秒、一弹指长达 7.2 秒。</p>
<p><strong>并发</strong></p>
<p>如下图所示，在大并发的情况下，所有的请求直接访问数据库，数据库会出现连接异常。</p>
<p>这个时候，就需要使用 Redis 做一个缓冲操作，让请求先访问到 Redis，而不是直接访问数据库。</p>
<p><img src="/2018/12/10/为什么分布式一定要有Redis？/2.webp" alt="img"></p>
<p>使用 Redis 有什么缺点</p>
<p>大家用 Redis 这么久，这个问题是必须要了解的，基本上使用 Redis 都会碰到一些问题，常见的也就几个。</p>
<p>回答主要是四个问题：</p>
<ul>
<li><strong>缓存和数据库双写一致性问题</strong></li>
<li><strong>缓存雪崩问题</strong></li>
<li><strong>缓存击穿问题</strong></li>
<li><strong>缓存的并发竞争问题</strong></li>
</ul>
<p>这四个问题，我个人觉得在项目中是常遇见的，具体解决方案，后文给出。</p>
<p>### </p>
<p>单线程的 Redis 为什么这么快</p>
<p>这个问题是对 Redis 内部机制的一个考察。根据我的面试经验，很多人都不知道Redis 是单线程工作模型。所以，这个问题还是应该要复习一下的。</p>
<p>回答主要是以下三点：</p>
<ul>
<li><strong>纯内存操作</strong></li>
<li><strong>单线程操作，避免了频繁的上下文切换</strong></li>
<li><strong>采用了非阻塞 I/O 多路复用机制</strong></li>
</ul>
<p><strong>题外话：</strong>我们现在要仔细的说一说 I/O 多路复用机制，因为这个说法实在是太通俗了，通俗到一般人都不懂是什么意思。</p>
<p><strong>打一个比方：</strong>小曲在 S 城开了一家快递店，负责同城快送服务。小曲因为资金限制，雇佣了一批快递员，然后小曲发现资金不够了，只够买一辆车送快递。</p>
<p><strong>经营方式一</strong></p>
<p>客户每送来一份快递，小曲就让一个快递员盯着，然后快递员开车去送快递。</p>
<p>慢慢的小曲就发现了这种经营方式存在下述问题：</p>
<ul>
<li>几十个快递员基本上时间都花在了抢车上了，大部分快递员都处在闲置状态，谁抢到了车，谁就能去送快递。</li>
<li>随着快递的增多，快递员也越来越多，小曲发现快递店里越来越挤，没办法雇佣新的快递员了。</li>
<li>快递员之间的协调很花时间。</li>
</ul>
<p>综合上述缺点，小曲痛定思痛，提出了下面的经营方式。</p>
<p><strong>经营方式二</strong></p>
<p>小曲只雇佣一个快递员。然后呢，客户送来的快递，小曲按送达地点标注好，然后依次放在一个地方。</p>
<p>最后，那个快递员依次的去取快递，一次拿一个，然后开着车去送快递，送好了就回来拿下一个快递。</p>
<p>上述两种经营方式对比，是不是明显觉得第二种，效率更高，更好呢？</p>
<p>在上述比喻中：</p>
<ul>
<li><strong>每个快递员→每个线程</strong></li>
<li><strong>每个快递→每个 Socket(I/O 流)</strong></li>
<li><strong>快递的送达地点→Socket 的不同状态</strong></li>
<li><strong>客户送快递请求→来自客户端的请求</strong></li>
<li><strong>小曲的经营方式→服务端运行的代码</strong></li>
<li><strong>一辆车→CPU 的核数</strong></li>
</ul>
<p>于是我们有如下结论：</p>
<ul>
<li><strong>经营方式一就是传统的并发模型，</strong>每个 I/O 流(快递)都有一个新的线程(快递员)管理。</li>
<li><strong>经营方式二就是 I/O 多路复用。</strong>只有单个线程(一个快递员)，通过跟踪每个 I/O 流的状态(每个快递的送达地点)，来管理多个 I/O 流。</li>
</ul>
<p>下面类比到真实的 Redis 线程模型，如图所示：</p>
<p><img src="/2018/12/10/为什么分布式一定要有Redis？/3.webp" alt="img"></p>
<p>简单来说，就是我们的 redis-client 在操作的时候，会产生具有不同事件类型的 Socket。</p>
<p>在服务端，有一段 I/O 多路复用程序，将其置入队列之中。然后，文件事件分派器，依次去队列中取，转发到不同的事件处理器中。</p>
<p>需要说明的是，这个 I/O 多路复用机制，Redis 还提供了 select、epoll、evport、kqueue 等多路复用函数库，大家可以自行去了解。</p>
<p>### </p>
<p>Redis 的数据类型，以及每种数据类型的使用场景</p>
<p>是不是觉得这个问题很基础？我也这么觉得。然而根据面试经验发现，至少百分之八十的人答不上这个问题。</p>
<p>建议，在项目中用到后，再类比记忆，体会更深，不要硬记。基本上，一个合格的程序员，五种类型都会用到。</p>
<p><strong>String</strong></p>
<p>这个没啥好说的，最常规的 set/get 操作，Value 可以是 String 也可以是数字。一般做一些复杂的计数功能的缓存。</p>
<p><strong>Hash</strong></p>
<p>这里 Value 存放的是结构化的对象，比较方便的就是操作其中的某个字段。</p>
<p>我在做单点登录的时候，就是用这种数据结构存储用户信息，以 CookieId 作为 Key，设置 30 分钟为缓存过期时间，能很好的模拟出类似 Session 的效果。</p>
<p><strong>List</strong></p>
<p>使用 List 的数据结构，可以做简单的消息队列的功能。另外还有一个就是，可以利用 lrange 命令，做基于 Redis 的分页功能，性能极佳，用户体验好。</p>
<p><strong>Set</strong></p>
<p>因为 Set 堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用 JVM 自带的 Set 进行去重？</p>
<p>因为我们的系统一般都是集群部署，使用 JVM 自带的 Set，比较麻烦，难道为了一个做一个全局去重，再起一个公共服务，太麻烦了。</p>
<p>另外，就是利用交集、并集、差集等操作，可以计算共同喜好，全部的喜好，自己独有的喜好等功能。</p>
<p><strong>Sorted Set</strong></p>
<p>Sorted Set多了一个权重参数 Score，集合中的元素能够按 Score 进行排列。</p>
<p>可以做排行榜应用，取 TOP N 操作。Sorted Set 可以用来做延时任务。最后一个应用就是可以做范围查找。</p>
<p>Redis 的过期策略以及内存淘汰机制</p>
<p>这个问题相当重要，到底 Redis 有没用到家，这个问题就可以看出来。</p>
<p>比如你 Redis 只能存 5G 数据，可是你写了 10G，那会删 5G 的数据。怎么删的，这个问题思考过么？</p>
<p>还有，你的数据已经设置了过期时间，但是时间到了，内存占用率还是比较高，有思考过原因么?</p>
<p><strong>回答：Redis 采用的是定期删除+惰性删除策略。</strong></p>
<p><strong>为什么不用定时删除策略</strong></p>
<p>定时删除，用一个定时器来负责监视 Key，过期则自动删除。虽然内存及时释放，但是十分消耗 CPU 资源。</p>
<p>在大并发请求下，CPU 要将时间应用在处理请求，而不是删除 Key，因此没有采用这一策略。</p>
<p><strong>定期删除+惰性删除是如何工作</strong></p>
<p>定期删除，Redis 默认每个 100ms 检查，是否有过期的 Key，有过期 Key 则删除。</p>
<p>需要说明的是，Redis 不是每个 100ms 将所有的 Key 检查一次，而是随机抽取进行检查(如果每隔 100ms，全部 Key 进行检查，Redis 岂不是卡死)。</p>
<p>因此，如果只采用定期删除策略，会导致很多 Key 到时间没有删除。于是，惰性删除派上用场。</p>
<p>也就是说在你获取某个 Key 的时候，Redis 会检查一下，这个 Key 如果设置了过期时间，那么是否过期了？如果过期了此时就会删除。</p>
<p>采用定期删除+惰性删除就没其他问题了么?</p>
<p>不是的，如果定期删除没删除 Key。然后你也没即时去请求 Key，也就是说惰性删除也没生效。这样，Redis的内存会越来越高。那么就应该采用内存淘汰机制。</p>
<p>在 redis.conf 中有一行配置：</p>
<p># maxmemory-policy volatile-lru</p>
<p>该配置就是配内存淘汰策略的(什么，你没配过？好好反省一下自己)：</p>
<ul>
<li><strong>noeviction：</strong>当内存不足以容纳新写入数据时，新写入操作会报错。应该没人用吧。</li>
<li><strong>allkeys-lru：</strong>当内存不足以容纳新写入数据时，在键空间中，移除最近最少使用的 Key。推荐使用，目前项目在用这种。</li>
<li><strong>allkeys-random：</strong>当内存不足以容纳新写入数据时，在键空间中，随机移除某个 Key。应该也没人用吧，你不删最少使用 Key，去随机删。</li>
<li><strong>volatile-lru：</strong>当内存不足以容纳新写入数据时，在设置了过期时间的键空间中，移除最近最少使用的 Key。这种情况一般是把 Redis 既当缓存，又做持久化存储的时候才用。不推荐。</li>
<li><strong>volatile-random：</strong>当内存不足以容纳新写入数据时，在设置了过期时间的键空间中，随机移除某个 Key。依然不推荐。</li>
<li><strong>volatile-ttl：</strong>当内存不足以容纳新写入数据时，在设置了过期时间的键空间中，有更早过期时间的 Key 优先移除。不推荐。</li>
</ul>
<p>PS：如果没有设置 expire 的 Key，不满足先决条件(prerequisites)；那么 volatile-lru，volatile-random 和 volatile-ttl 策略的行为，和 noeviction(不删除) 基本上一致。</p>
<p>### </p>
<p>Redis 和数据库双写一致性问题</p>
<h3 id=""><a href="#" class="headerlink" title=" "></a> </h3><p>一致性问题是分布式常见问题，还可以再分为最终一致性和强一致性。数据库和缓存双写，就必然会存在不一致的问题。</p>
<p>答这个问题，先明白一个前提。就是如果对数据有强一致性要求，不能放缓存。我们所做的一切，只能保证最终一致性。</p>
<p>另外，我们所做的方案从根本上来说，只能说降低不一致发生的概率，无法完全避免。因此，有强一致性要求的数据，不能放缓存。</p>
<p><strong>回答：</strong>首先，采取正确更新策略，先更新数据库，再删缓存。其次，因为可能存在删除缓存失败的问题，提供一个补偿措施即可，例如利用消息队列。</p>
<p>### </p>
<p>如何应对缓存穿透和缓存雪崩问题</p>
<h3 id="-1"><a href="#-1" class="headerlink" title=" "></a> </h3><p>这两个问题，说句实在话，一般中小型传统软件企业，很难碰到这个问题。如果有大并发的项目，流量有几百万左右。这两个问题一定要深刻考虑。</p>
<p><strong>缓存穿透，</strong>即黑客故意去请求缓存中不存在的数据，导致所有的请求都怼到数据库上，从而数据库连接异常。</p>
<p>缓存穿透解决方案：</p>
<ul>
<li><strong>利用互斥锁，</strong>缓存失效的时候，先去获得锁，得到锁了，再去请求数据库。没得到锁，则休眠一段时间重试。</li>
<li><strong>采用异步更新策略，无论 Key 是否取到值，都直接返回。</strong>Value 值中维护一个缓存失效时间，缓存如果过期，异步起一个线程去读数据库，更新缓存。需要做缓存预热(项目启动前，先加载缓存)操作。</li>
<li><strong>提供一个能迅速判断请求是否有效的拦截机制，</strong>比如，利用布隆过滤器，内部维护一系列合法有效的 Key。迅速判断出，请求所携带的 Key 是否合法有效。如果不合法，则直接返回。</li>
</ul>
<p><strong>缓存雪崩，</strong>即缓存同一时间大面积的失效，这个时候又来了一波请求，结果请求都怼到数据库上，从而导致数据库连接异常。</p>
<p>缓存雪崩解决方案：</p>
<ul>
<li><p><strong>给缓存的失效时间，</strong>加上一个随机值，避免集体失效。</p>
</li>
<li><p><strong>使用互斥锁，</strong>但是该方案吞吐量明显下降了。</p>
</li>
<li><p><strong>双缓存。</strong>我们有两个缓存，缓存 A 和缓存 B。缓存 A 的失效时间为 20 分钟，缓存 B 不设失效时间。自己做缓存预热操作。</p>
<p>然后细分以下几个小点：从缓存 A 读数据库，有则直接返回；A 没有数据，直接从 B 读数据，直接返回，并且异步启动一个更新线程，更新线程同时更新缓存 A 和缓存 B。</p>
</li>
</ul>
<p>### </p>
<p>如何解决 Redis 的并发竞争 Key 问题</p>
<h3 id="-2"><a href="#-2" class="headerlink" title=" "></a> </h3><p>这个问题大致就是，同时有多个子系统去 Set 一个 Key。这个时候大家思考过要注意什么呢？</p>
<p>需要说明一下，我提前百度了一下，发现答案基本都是推荐用 Redis 事务机制。</p>
<p>我并不推荐使用 Redis 的事务机制。因为我们的生产环境，基本都是 Redis 集群环境，做了数据分片操作。</p>
<p>你一个事务中有涉及到多个 Key 操作的时候，这多个 Key 不一定都存储在同一个 redis-server 上。因此，Redis 的事务机制，十分鸡肋。</p>
<p><strong>如果对这个 Key 操作，不要求顺序</strong></p>
<p>这种情况下，准备一个分布式锁，大家去抢锁，抢到锁就做 set 操作即可，比较简单。</p>
<p><strong>如果对这个 Key 操作，要求顺序</strong></p>
<p>假设有一个 key1，系统 A 需要将 key1 设置为 valueA，系统 B 需要将 key1 设置为 valueB，系统 C 需要将 key1 设置为 valueC。</p>
<p>期望按照 key1 的 value 值按照 valueA &gt; valueB &gt; valueC 的顺序变化。这种时候我们在数据写入数据库的时候，需要保存一个时间戳。</p>
<p>假设时间戳如下：</p>
<p>系统A key 1 {valueA  3:00}<br>系统B key 1 {valueB  3:05}<br>系统C key 1 {valueC  3:10}</p>
<p>那么，假设这会系统 B 先抢到锁，将 key1 设置为{valueB 3:05}。接下来系统 A 抢到锁，发现自己的 valueA 的时间戳早于缓存中的时间戳，那就不做 set 操作了，以此类推。</p>
<p>其他方法，比如利用队列，将 set 方法变成串行访问也可以。总之，灵活变通。</p>
<p>总结</p>
<p>本文对 Redis 的常见问题做了一个总结。大部分是自己在工作中遇到，以及之前面试别人的时候，爱问的一些问题。</p>
<p>另外，不推荐大家临时抱佛脚，真正碰到一些有经验的工程师，其实几下就能把你问懵。最后，希望大家有所收获吧。</p>

        
        </div>
        <footer class="article-footer">
            
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/Redis/">Redis</a>, <a class="tag-link" href="/tags/转载/">转载</a>
    </div>

            <div class="share-container">



</div>

    <!--
<a data-url="https://ylfjmy.gitee.io/2018/12/10/为什么分布式一定要有Redis？/" data-id="cktmb8pul001qf0p6wngdxvqy" class="article-share-link"><i class="fa fa-share"></i>分享到</a>
<script>
    (function ($) {
        // Prevent duplicate binding
        if (typeof(__SHARE_BUTTON_BINDED__) === 'undefined' || !__SHARE_BUTTON_BINDED__) {
            __SHARE_BUTTON_BINDED__ = true;
        } else {
            return;
        }
        $('body').on('click', function() {
            $('.article-share-box.on').removeClass('on');
        }).on('click', '.article-share-link', function(e) {
            e.stopPropagation();

            var $this = $(this),
                url = $this.attr('data-url'),
                encodedUrl = encodeURIComponent(url),
                id = 'article-share-box-' + $this.attr('data-id'),
                offset = $this.offset(),
                box;

            if ($('#' + id).length) {
                box = $('#' + id);

                if (box.hasClass('on')){
                    box.removeClass('on');
                    return;
                }
            } else {
                var html = [
                    '<div id="' + id + '" class="article-share-box">',
                        '<input class="article-share-input" value="' + url + '">',
                        '<div class="article-share-links">',
                            '<a href="https://twitter.com/intent/tweet?url=' + encodedUrl + '" class="fa fa-twitter article-share-twitter" target="_blank" title="Twitter"></a>',
                            '<a href="https://www.facebook.com/sharer.php?u=' + encodedUrl + '" class="fa fa-facebook article-share-facebook" target="_blank" title="Facebook"></a>',
                            '<a href="http://pinterest.com/pin/create/button/?url=' + encodedUrl + '" class="fa fa-pinterest article-share-pinterest" target="_blank" title="Pinterest"></a>',
                            '<a href="https://plus.google.com/share?url=' + encodedUrl + '" class="fa fa-google article-share-google" target="_blank" title="Google+"></a>',
                        '</div>',
                    '</div>'
                ].join('');

              box = $(html);

              $('body').append(box);
            }

            $('.article-share-box.on').hide();

            box.css({
                top: offset.top + 25,
                left: offset.left
            }).addClass('on');

        }).on('click', '.article-share-box', function (e) {
            e.stopPropagation();
        }).on('click', '.article-share-box-input', function () {
            $(this).select();
        }).on('click', '.article-share-box-link', function (e) {
            e.preventDefault();
            e.stopPropagation();

            window.open(this.href, 'article-share-box-window-' + Date.now(), 'width=500,height=450');
        });
    })(jQuery);
</script>
-->

            
    

        </footer>
    </div>
    
        
<nav id="article-nav">
    
        <a href="/2018/12/10/Markdown颜色/" id="article-nav-newer" class="article-nav-link-wrap">
            <strong class="article-nav-caption">上一篇</strong>
            <div class="article-nav-title">
                
                    Markdown颜色
                
            </div>
        </a>
    
    
        <a href="/2018/09/26/redis/" id="article-nav-older" class="article-nav-link-wrap">
            <strong class="article-nav-caption">下一篇</strong>
            <div class="article-nav-title">Redis常用命令汇总</div>
        </a>
    
</nav>


    
</article>


    <!--

    <section id="comments">
    
    </section>

-->
</section>
            
                <aside id="sidebar">
   
        
    <div class="widget-wrap">
        <h3 class="widget-title">分类</h3>
        <div class="widget">
            <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Docker/">Docker</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java/">Java</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Linux/">Linux</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/MySQL/">MySQL</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Redis/">Redis</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/其它/">其它</a><span class="category-list-count">1</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">归档</h3>
        <div class="widget">
            <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/09/">九月 2021</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/12/">十二月 2018</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/09/">九月 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/08/">八月 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/07/">七月 2018</a><span class="archive-list-count">2</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">标签</h3>
        <div class="widget">
            <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Docker/">Docker</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java/">Java</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Linux/">Linux</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/MySQL/">MySQL</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Redis/">Redis</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/其它/">其它</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/原创/">原创</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/转载/">转载</a><span class="tag-list-count">3</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">标签云</h3>
        <div class="widget tagcloud">
            <a href="/tags/Docker/" style="font-size: 10px;">Docker</a> <a href="/tags/Java/" style="font-size: 10px;">Java</a> <a href="/tags/Linux/" style="font-size: 13.33px;">Linux</a> <a href="/tags/MySQL/" style="font-size: 13.33px;">MySQL</a> <a href="/tags/Redis/" style="font-size: 13.33px;">Redis</a> <a href="/tags/git/" style="font-size: 10px;">git</a> <a href="/tags/其它/" style="font-size: 10px;">其它</a> <a href="/tags/原创/" style="font-size: 20px;">原创</a> <a href="/tags/转载/" style="font-size: 16.67px;">转载</a>
        </div>
    </div>

    
        
    <div class="widget-wrap widget-list">
        <h3 class="widget-title">链接</h3>
        <div class="widget">
            <ul>
                
                    <li>
                        <a href="http://hexo.io">Hexo</a>
                    </li>
                
            </ul>
        </div>
    </div>


    
    <div id="toTop" class="fa fa-angle-up"></div>
</aside>
            
        </div>
        <!--<footer id="footer">
    <div class="outer">
        <div id="footer-info" class="inner">
            &copy; 2021 Zhang Bo<br>
            Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>. Theme by <a href="http://github.com/ppoffice">PPOffice</a>
        </div>
    </div>
</footer>-->
        

    
        <script src="/vendor/lightgallery/js/lightgallery.min.js"></script>
        <script src="/vendor/lightgallery/js/lg-thumbnail.min.js"></script>
        <script src="/vendor/lightgallery/js/lg-pager.min.js"></script>
        <script src="/vendor/lightgallery/js/lg-autoplay.min.js"></script>
        <script src="/vendor/lightgallery/js/lg-fullscreen.min.js"></script>
        <script src="/vendor/lightgallery/js/lg-zoom.min.js"></script>
        <script src="/vendor/lightgallery/js/lg-hash.min.js"></script>
        <script src="/vendor/lightgallery/js/lg-share.min.js"></script>
        <script src="/vendor/lightgallery/js/lg-video.min.js"></script>
    
    



<!-- Custom Scripts -->
<script src="/js/main.js"></script>

    </div>
</body>
</html>